﻿using System;

namespace _32._1_CSharp_面向对象_委托
{
    class Program
    {
        static void Main(string[] args)
        {
            var boy = new Student("小A");
            var girl = new Girl("小小");
            var tech = new Teacher("TS");
            var bro = new Bro();

            // 委托如果连续使用 = 赋值，会发生覆盖，只能执行最后赋值的那个方法
            // 在本情境中出现了委托的分发的需求 （委托的多播）
            // 实现委托的多播：+= 添加（叠加的过程）；-= 移除
            // 多播委托事件监听的顺序决定了执行和输出的顺序

            //当使用 自己实现的属性的话，需要使用等号，一定不能使用 += ，否则会重复添加
            bro.OnFoodReached = girl.Do;
            bro.OnFoodReached = girl.Do;
            bro.OnFoodReached = girl.Do;
            bro.OnFoodReached = tech.Do;
            bro.OnFoodReached = tech.Do;
            bro.OnFoodReached = tech.Do;
            bro.OnFoodReached = tech.Do;
            bro.OnFoodReached = boy.Do; // 监听，注册
            bro.OnFoodReached = boy.Do; // 监听，注册
            bro.OnFoodReached = boy.Do; // 监听，注册
            bro.OnFoodReached = boy.Do; // 监听，注册

            bro.ReportPositon(50);
            Console.WriteLine("-------分割--------");
            bro.ReportPositon(15);
        }
    }
    // 委托一般用于观察者模式（监听模式）
    // 理解观察者模式： 观察者、被观察者，如果被观察者有出现 观察者关心的动作 ，观察者也会采取措施

    // 等外卖:
    // 被观察者：外卖小哥
    // 观察者： 你
    // 关心的动作：外卖小哥离我 20 米
    //  观察者的行为：准备好开饭了

    //  第二个观察者：女朋友
    //  观察者的行为：云共餐

    //   第三个观察者：老师
    //   观察者的行为：督促专心的听讲

    public delegate void 外卖到了();

    class Person
    {
        public string name;
        public Person(string name) => this.name = name;
        public virtual void Do()
        {
        }
    }

    /// <summary>
    ///  学生
    /// </summary>
    class Student : Person
    {
        public Student(string name) :base(name){ }
        public override void Do()
        {
            Console.WriteLine($"xxx：餐要到了，准备接餐");
        }
    }

    /// <summary>
    /// 女孩
    /// </summary>
    class Girl : Person
    {
        public override void Do()
        {
            Console.WriteLine("女朋友：我要和 xxx 云共餐");
        }
        public Girl(string name) : base(name) { }
    }
    /// <summary>
    /// 老师
    /// </summary>
    class Teacher : Person
    {
        public Teacher(string name) : base(name) { }
        public override void Do()
        {
            Console.WriteLine("老师：点餐的 xxx 专心听讲");
        }
    }


    /// <summary>
    /// 小哥
    /// </summary>
    class Bro // 兄弟 brother 的缩写
    {
        /// <summary>
        /// 事件：当食物到达的时候委托
        /// </summary>
        // On :当 xxxx 的时候
        // Food ：食物
        // Reached :到达
        private 外卖到了 onFoodReached;
        public 外卖到了 OnFoodReached
        {
            get => onFoodReached;
            set
            {
                if (onFoodReached == null)
                {
                    onFoodReached += value;
                }
                else
                {
                    var list = onFoodReached.GetInvocationList();
                    // 联合查询
                    var result = Array.Find(list, v =>
                     {
                         var b = v.Method.Name == "Do" && v.Target == value.Target;
                         return b;
                     });

                    if (result == null)
                    {
                        onFoodReached += value;
                    }
                    else
                    {
                        Console.WriteLine($"{value.Target.GetType().Name}  - 重复添加了 {value.Method.Name} !!");
                        if (value.Target is Girl girl)
                        {
                            Console.WriteLine($"{girl.name} 你不要搞事情了~");
                        }
                        else if (value.Target is  Teacher teacher)
                        {
                            Console.WriteLine($"{teacher.name} , 老师您悠着点~");
                        }
                        else 
                        {
                            Console.WriteLine("看着办，你罗嗦了");
                        }
                    }
                }
            }
        }



        /// <summary>
        /// 报告位置
        /// </summary>
        /// <param name="distance">小哥上传的距离</param>
        public void ReportPositon(int distance)
        {
            if (distance <= 20)
            {
                Console.WriteLine($"小哥：距离客户 {distance} 米,请准备接餐");
                OnFoodReached?.Invoke();
            }
            else
            {
                Console.WriteLine($"小哥：距离客户 {distance} 米,请耐心等待");
            }
        }
    }
}
